﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.Contracts;
using System.Linq;
using Socium.Domain.Collections;

namespace Socium.Presentation {
	public abstract class TreeItemBase<TModel> : NamedViewModel, ITreeItem where TModel : class {
		protected TreeItemBase(TModel model) {
			_model = model;
			DisplayName = GetDisplayName(model);
		}

		readonly TModel _model;


		IEnumerable<ITreeItem> ITreeItem.Childeren {
			get { return Childeren; }
		}

		public IEnumerable<ITreeItem> Childeren {
			get { return Enumerable.Empty<ITreeItem>(); }
		}

		public abstract IEnumerable<CommandViewModel> Commands { get; }

		public TModel Model {
			get { return _model; }
		}

		public void Update() {
			DisplayName = GetDisplayName(Model);
		}

		[Pure]
		protected abstract string GetDisplayName(TModel model);

		public ITreeItem Parent { get; set; }

		public void Details<T>(IFormViewService form_view_service, Func<TModel, T> form_creator) where T : FormViewModel<TModel> {
			var view_model = form_creator(_model);
			view_model.ModelUpdated += Update;

			form_view_service.Show(view_model);
		} 
	}

	public abstract class TreeItemBase<TModel, TChild> : TreeItemBase<TModel> where TChild : class, ITreeItem where TModel : class {
		protected TreeItemBase(TModel model) : base(model) {
			var observable_collection = new ObservableCollection<TChild>();
			observable_collection.AddRange(GetInitalChilderen(model));
			observable_collection.Iterate(SetParent);

			observable_collection.CollectionChanged += (sender, e) => OnCollectionChanged(e);

			Childeren = observable_collection;
		}

		void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
			var old_items = e.OldItems;
			if (old_items != null) {
				foreach (TChild old_item in old_items) {
					old_item.Parent = null;
					OnItemRemoved(old_item);
				}
			}

			var new_items = e.NewItems;
			if (new_items != null) {
				foreach (TChild new_item in new_items) {
					SetParent(new_item);
					OnItemAdded(new_item);
				}
			}
		}

		void SetParent(TChild new_item) {
			if (new_item.Parent != null) {
				throw new ArgumentException();
			}

			new_item.Parent = this;
		}

		public new ICollection<TChild> Childeren { get; private set; }

		[Pure]
		protected abstract IEnumerable<TChild> GetInitalChilderen(TModel model);

		protected abstract void OnItemAdded(TChild item);
		protected abstract void OnItemRemoved(TChild item);

		public void NewChild<TFormViewModel, TChildModel>(IFormViewService form_view_service, Func<TChildModel, TChild> child_creator)
			where TChildModel : class
			where TFormViewModel : FormViewModel<TChildModel>, new()
		{
			var view_model = new TFormViewModel();
			view_model.ModelCreated += model => {
				var item = child_creator(model);
				view_model.ModelUpdated += item.Update;

				Childeren.Add(item);
			};

			form_view_service.Show(view_model);
		}
	}
}
